﻿"""Security helpers for hashing and JWT creation."""

from __future__ import annotations

from datetime import datetime, timedelta, timezone
from typing import Any, cast

from fastapi import HTTPException, status
import logging
from jose import JWTError, jwt
import bcrypt

from ..core.config import settings


def verify_password(plain_password: str, hashed_password: str) -> bool:
    """安全验证密码。

    使用 bcrypt 直接验证，避免 passlib 兼容性问题。
    bcrypt 限制密码最多 72 字节，自动截断以避免异常。
    """
    try:
        # bcrypt has a 72-byte limit, truncate password if needed
        password_bytes = plain_password.encode('utf-8')
        if len(password_bytes) > 72:
            password_bytes = password_bytes[:72]

        hashed_bytes = hashed_password.encode('utf-8')
        return bcrypt.checkpw(password_bytes, hashed_bytes)
    except Exception as exc:  # pragma: no cover
        logging.getLogger(__name__).warning("Password verification error suppressed: %s", exc)
        return False


def get_password_hash(password: str) -> str:
    """生成密码哈希。

    使用 bcrypt 直接生成哈希，避免 passlib 兼容性问题。
    bcrypt 限制密码最多 72 字节，自动截断以避免异常。
    """
    # bcrypt has a 72-byte limit, truncate password if needed
    password_bytes = password.encode('utf-8')
    if len(password_bytes) > 72:
        password_bytes = password_bytes[:72]

    salt = bcrypt.gensalt()
    hashed = bcrypt.hashpw(password_bytes, salt)
    return hashed.decode('utf-8')


def create_access_token(subject: str, token_type: str, expires_delta: timedelta) -> str:
    now = datetime.now(timezone.utc)
    payload: dict[str, Any] = {
        "sub": subject,
        "type": token_type,
        "iat": now,
        "exp": now + expires_delta,
    }
    return str(jwt.encode(payload, settings.SECRET_KEY, algorithm="HS256"))


def decode_token(token: str, expected_type: str | None = None) -> dict[str, Any]:
    try:
        payload: dict[str, Any] = jwt.decode(token, settings.SECRET_KEY, algorithms=["HS256"])
    except JWTError as exc:
        raise HTTPException(
            status_code=status.HTTP_401_UNAUTHORIZED, detail="Invalid token"
        ) from exc
    token_type = payload.get("type")
    if expected_type and token_type != expected_type:
        raise HTTPException(status_code=status.HTTP_401_UNAUTHORIZED, detail="Invalid token type")
    # jose.jwt.decode 已经返回 dict[str, Any]，无需额外 cast
    return payload
